import core.Line;
import core.Station;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("Проверка рассчёта маршрутов")
public class RouteCalculatorTest {
    private StationIndex stationIndex;
    private RouteCalculator routeCalculator;
    private TreeMap<String, Station> stations;

    @BeforeEach
    void beforeEach() {
        stationIndex = new StationIndex();

        Line[] lines = new Line[] {
                new Line(1, "First Line"),
                new Line(2, "Second Line"),
                new Line(3, "Third Line")
        };

        for (Line line : lines) {
            stationIndex.addLine(line);
        }

        stations = new TreeMap<>();
        stations.put("11", new Station("11", lines[0]));
        stations.put("12", new Station("12", lines[0]));
        stations.put("13", new Station("13", lines[0]));
        stations.put("21", new Station("21", lines[1]));
        stations.put("22", new Station("22", lines[1]));
        stations.put("31", new Station("31", lines[2]));
        stations.put("32", new Station("32", lines[2]));
        stations.put("33", new Station("33", lines[2]));

        for (Station station : stations.values()) {
            stationIndex.addStation(station);
            station.getLine().addStation(station);
        }

        ArrayList<Station> connection = new ArrayList<>();
        connection.add(stations.get("13"));
        connection.add(stations.get("21"));
        stationIndex.addConnection(connection);

        connection.clear();
        connection.add(stations.get("22"));
        connection.add(stations.get("31"));
        stationIndex.addConnection(connection);

        routeCalculator = new RouteCalculator(stationIndex);
    }

    @Test
    @DisplayName("Маршрут без пересадок")
    void getRouteOnTheLine() {
        List<Station> actual = routeCalculator.getShortestRoute(
                stationIndex.getStation("13", 1),
                stationIndex.getStation("11", 1)
        );

        List<Station> expected = List.of(
                stations.get("13"),
                stations.get("12"),
                stations.get("11")
        );

        assertEquals(expected, actual);
    }

    @Test
    @DisplayName("Маршрут с одной пересадкой")
    void getRouteWithOneConnection() {
        List<Station> actual = routeCalculator.getShortestRoute(
                stationIndex.getStation("11", 1),
                stationIndex.getStation("22", 2)
        );

        List<Station> expected = List.of(
                stations.get("11"),
                stations.get("12"),
                stations.get("13"),
                stations.get("21"),
                stations.get("22")
        );

        assertEquals(expected, actual);
    }

    @Test
    @DisplayName("Маршрут с двумя пересадками")
    void getRouteWithTwoConnections() {
        List<Station> actual = routeCalculator.getShortestRoute(
                stationIndex.getStation("11", 1),
                stationIndex.getStation("33", 3)
        );

        List<Station> expected = List.of(
                stations.get("11"),
                stations.get("12"),
                stations.get("13"),
                stations.get("21"),
                stations.get("22"),
                stations.get("31"),
                stations.get("32"),
                stations.get("33")
        );

        assertEquals(expected, actual);
    }

    @Test
    @DisplayName("Длительность маршрута")
    void calculateDuration() {
        double actual = RouteCalculator.calculateDuration(
                List.of(
                        stations.get("11"),
                        stations.get("12"),
                        stations.get("13"),
                        stations.get("21"),
                        stations.get("22"),
                        stations.get("31"),
                        stations.get("32"),
                        stations.get("33")
                )
        );

        double expected = 2.5 + 2.5 + 3.5 + 2.5 + 3.5 + 2.5 + 2.5;

        assertEquals(expected, actual);
    }
}
